package sis.studentinfotest;

import junit.framework.TestCase;
import sis.studentinfo.*;

import java.util.Random;
import java.util.logging.Handler;
import java.util.logging.Logger;

public class StudentTest extends TestCase {
    private static final double GRADE_TOLERANCE = 0.05;

    public void testCreate() {
        final String firstStudentName = "张 三 风 ";
        Student student = new Student(firstStudentName);
        assertEquals("张", student.getFirstName());
        assertEquals("三", student.getMiddleName());
        assertEquals("风", student.getLastName());

        final String firstStudentName2 = "张 三  ";
        Student student2 = new Student(firstStudentName2);
        assertEquals("张", student2.getFirstName());
        assertEquals("三", student2.getLastName());

        final String firstStudentName3 = "三  ";
        Student student3 = new Student(firstStudentName3);
        assertEquals("三", student3.getLastName());

    }


    public void testCredits() {
        Student student = new Student("小明");
        assertEquals(0, student.getCredits());
        student.addCredits(3);
        assertEquals(3, student.getCredits());
        student.addCredits(4);
        assertEquals(7, student.getCredits());
        student.addCredits(5);
        assertEquals(12, student.getCredits());
        assertTrue(student.isFullTime());
    }

    public void testStudentStatus() {
        Student student = new Student("小明");
        assertEquals(0, student.getCredits());
        assertFalse(student.isFullTime());

        student.addCredits(3);
        assertEquals(3, student.getCredits());
        assertFalse(student.isFullTime());

        student.addCredits(4);
        assertEquals(7, student.getCredits());
        assertFalse(student.isFullTime());

        student.addCredits(5);
        assertEquals(Student.CREDITS_REQUIRED_FOR_FULL_TIME, student.getCredits());

        assertTrue(student.isFullTime());
    }

    public void testInState() {
        Student student = new Student("a");
        assertFalse(student.isInState());
        student.setState(Student.IN_STATE);
        assertTrue((student.isInState()));
        student.setState("MD");
        assertFalse(student.isInState());
    }

    public void testCalculateGpa() {
        Student student = new Student("小明");
        assertGpa(student, 0.0);
        student.addGrade(Student.Grade.A);
        assertGpa(student, 4.0);
        student.addGrade(Student.Grade.B);
        assertGpa(student, 3.5);
        student.addGrade(Student.Grade.C);
        assertGpa(student, 3.0);
        student.addGrade(Student.Grade.D);
        assertGpa(student, 2.5);
    }

    private void assertGpa(Student student, double expectedGpa) {
        assertEquals(expectedGpa, student.getGpa(), GRADE_TOLERANCE);
    }

    public void testCalculateHonorsStudentGpa() {

        assertGpa(createHonorsStudent(), 0.0);
        assertGpa(createHonorsStudent(Student.Grade.A), 5.0);
        assertGpa(createHonorsStudent(Student.Grade.B), 4.0);
        assertGpa(createHonorsStudent(Student.Grade.C), 3.0);
        assertGpa(createHonorsStudent(Student.Grade.D), 2.0);

        Student student = createHonorsStudent();
        student.addGrade(Student.Grade.A);
        student.addGrade(Student.Grade.B);
        assertGpa(student, 4.5);
    }

    public void testEliteGradingStrategy() {
        Student student = new Student("张三");
        student.setGradingStrategy(new EliteGradingStrategy());
        student.addGrade(Student.Grade.A);
        student.addGrade(Student.Grade.B);
        assertGpa(student, 5.5);
    }

    private Student createHonorsStudent(Student.Grade grade) {
        Student student = createHonorsStudent();
        student.addGrade(grade);
        return student;
    }

    private Student createHonorsStudent() {
        Student student = new Student("张三");
        student.setGradingStrategy(new HonorsGradingStrategy());
        return student;
    }

    public void testCharges() {
        Student student = new Student("a");
        student.addCharge(500);
        student.addCharge(200);
        student.addCharge(399);
        assertEquals(1099, student.totalCharges());
    }

    public void testBadlyFormattedName() {
        Handler handler = new TestHandler();
        Student.logger.addHandler(handler);
        final String studentName = "a b c d";
        try {
            new Student(studentName);
            fail("expected exception from 4-part name");
        } catch (StudentNameFormatException e) {
            String message = String.format(Student.TOO_MANY_NAME_PARTS_MSG, studentName, Student.MAX_NAME_PARTS);
            assertEquals(message, e.getMessage());
            assertEquals(message,((TestHandler) handler).getMessage());
        }
    }

    private boolean wasLogged(String message,TestHandler handler) {
        return message.equals(handler.getMessage());
    }

    public void testLoggingHierarchy(){
        Logger logger = Logger.getLogger("sis.studentinfo.Student");
        assertTrue(logger == Logger.getLogger("sis.studentinfo.Student"));

        Logger parent = Logger.getLogger("sis.studentinfo");
        assertEquals(parent,logger.getParent());
        assertEquals(Logger.getLogger("sis"),parent.getParent());
    }


}
